package com.qf.controller;

import com.qf.captcha.CaptchaCodeManager;
import com.qf.pojo.DtsAdmin;
import com.qf.service.DtsPermissionService;
import com.qf.service.DtsRoleService;
import com.qf.util.*;
import com.qf.util.Base64;
import com.qf.util.UUID;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;

import java.io.ByteArrayOutputStream;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 后端管理---认证管理
 *   百度云盘：  100M 带宽
 *   上行： 上传 2.3m/s
 *   下行： 下载 999kB/s
 *
 *
 *    接口文档 ： 对接入口的文档  简称 ： 接口文档
 *    Vue（前端）  对接入口的文档      Java（后端）
 *    前端工程师 代表           后端工程师（代表）    开会     形成文档
 *
 * @author lixu
 */
@RestController
@RequestMapping("/admin/auth")
@CrossOrigin
@Slf4j
public class AdminAuthController {

    @Autowired
    private DtsRoleService dtsRoleService;
    @Autowired
    private DtsPermissionService dtsPermissionService;
    @Autowired
    private ApplicationContext ac;
    /**
     * 获取验证码
     * http://localhost:8080/admin/auth/captchaImage
     *
     * res.data.data.img == Map.data.img
     **              生成验证码的数字
     *      *              将数字生成图片
     *      *              将图片转成二进制
     *      *              使用Base64将二进制转编码    "/9j/4AAQSkZJRlZ/2Q=="
     * JSON串
     * {
     *     "errno":0,
     *  	"data":	  {Map对象
     *           "img":"/9j/4AAQSkZJRlZ/2Q==",  验证码
     *           "uuid":"b5ca22d8b9e14a88b2851da906d19e4f"
     *         },
     *     "errmsg":"成功"
     * }
     *
     *
     * Cookie：没有
     * Session：就算有 也找不到
     * 验证码：保存在Session中吗？  Map保存   K:uuid   ：V:1234
     */
    @GetMapping("/captchaImage")
    public Object captchaImage() throws Exception{

        //1:验证码数字
        String code = VerifyCodeUtils.generateVerifyCode(4);
        //2:缓存验证码的数字
        String uuid = UUID.randomUUID().toString();
        boolean isSuccess = CaptchaCodeManager.addToCache(uuid, code, null);
        if(!isSuccess){
            log.error("【登录模块】生成验证码保存失败!验证码是:{}",code);//{}：占位
            return ResponseUtil.fail();// -1 错误
        }
        //3:将验证码的数字生成图片
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        //宽
        //高
        //图片是流或是二进制
        //验证码数字
        VerifyCodeUtils.outputImage(116,40,os,code);

        //4:将流转成二进制  使用Base64转编码
        String codeImg = Base64.encode(os.toByteArray());
        //返回值
        Map data = new HashMap<>();
        data.put("img",codeImg);
        data.put("uuid",uuid);
        return ResponseUtil.ok(data);
    }
    /**
     *- 登录请求地址 : http://localhost:8083/admin/auth  /login
     * - POST请求
     * - 上行数据:  接收页面传递过来的 DTO
     * {
     * 	"code": "66e8",
     * 	"password": "123456",
     * 	"username": "qianfeng",
     * 	"uuid": "cab317c6-1bf1-436d-96ac-fda9f8d37dde"
     * }
     * 方案1： AdminDTO  同学们自己写
     * 方案2： 直接接收 JSON串
     *      JacksonUtils工具类获取出 四个属性
     */
    @PostMapping("/login")
    public Object login(@RequestBody String body){
        //1:接收到了页面传递过来的参数
        String username = JacksonUtil.parseString(body, "username");
        String password = JacksonUtil.parseString(body, "password");
        String code = JacksonUtil.parseString(body, "code");
        String uuid = JacksonUtil.parseString(body, "uuid");
        if(StringUtils.isEmpty(code)){
            return AdminResponseUtil.fail(807,"验证码不能为空");
        }
        if(StringUtils.isEmpty(username)){
            return AdminResponseUtil.fail(808,"用户名不能为空");
        }
        //其它同学们完成 了
        //2:校验验证码
        String cachedCaptcha = CaptchaCodeManager.getCachedCaptcha(uuid);
        if(StringUtils.isEmpty(cachedCaptcha)){
            return AdminResponseUtil.fail(AdminResponseCode.AUTH_CAPTCHA_EXPIRED);//验证码过期
        }
  /*      if(!cachedCaptcha.equalsIgnoreCase(code)){
            //验证码不正确
            return AdminResponseUtil.fail(AdminResponseCode.AUTH_CAPTCHA_ERROR); //验证码不正确
        }*/
        //3：校验用户名及密码 Shiro
        Subject subject = SecurityUtils.getSubject();
        //加密 MD5Hash Shiro自带   本次BCrypt  明文与密文直接比较
        UsernamePasswordToken usernamePasswordToken  =
                 new UsernamePasswordToken(username,password);
        //登录
        try{
            subject.login(usernamePasswordToken);//底层 realm 连接Mysql数据库 校验用户名及密码
        }catch (UnknownAccountException e){
            return AdminResponseUtil.fail(AdminResponseCode.ADMIN_INVALID_ACCOUNT_ERR);
        }catch (IncorrectCredentialsException e){
            return AdminResponseUtil.fail(AdminResponseCode.ADMIN_INVALID_PASSWORD_ERR);
        }catch (LockedAccountException e){
            return AdminResponseUtil.fail(AdminResponseCode.ADMIN_LOCK_ACCOUNT);
        }

        /**
         * 下行数据
         * {
         *     "errno":0,
         *  	"data":"568f6dd8-97c7-450d-a00b-0a01c3b930c7", //是当前用户Session的ID
         *  	"errmsg":"成功"
         * }
         */
        return ResponseUtil.ok(subject.getSession().getId());
    }
    /**
     * 登录之后 获胜用户信息
     * - 登录后获取用户名, 角色, 权限详细信息地址 : http://localhost:8083/admin/auth/info
     * - GET请求
     * - 下行数据 :
     * {
     *     "errno":0,
     *     "data":{
     *         "name":"qianfeng",
     *         "roles":["超级管理员","商场管理员","推广管理员","品牌制造商"], Set<String></String>
     *         "perms":["GET /admin/keyword/list","GET /admin/keyword/list","GET /admin/keyword/list"],
     *         "avatar":"https://dss1.bdstatic.com/6OF1,499686101&fm=85&app=79&f=JPEG?w=121&h=75&s=81B24C32D40"
     *     },
     *     "errmsg":"成功"
     * }
     */
    @GetMapping("/info")
    public Object info(){
        Map map = new HashMap();

        //1:获取用户名
        Subject subject = SecurityUtils.getSubject();
        DtsAdmin dtsAdmin = (DtsAdmin) subject.getPrincipal();
        map.put("name",dtsAdmin.getUsername());
        //2:头像
        map.put("avatar",dtsAdmin.getAvatar());
        //3:角色集合 或数组
        //管理员的ID
        //Integer id = dtsAdmin.getId();
        Integer[] roleIds = dtsAdmin.getRoleIds();
        Set<String> roles = dtsRoleService.findDtsRoleNameByIds(roleIds);
        System.out.println("roles:" + roles);
        map.put("roles",roles);
        //4:权限 集合
        Set<String> perms = dtsPermissionService.findDtsPermsPermissionByRoleIds(roleIds);
        System.out.println("perms:" + perms);
        //5:将后端代码中的admin:goods:update权限 【转换】 成 GET /admin/keyword/list  api
        Collection<String> permsApi = toApi(perms);
        //表示：等项目开发个差不多 就可以进行权限转换了
        map.put("perms", permsApi);
        return ResponseUtil.ok(map);
    }

    /**
     * 将后端代码中的admin:goods:update权限 【转换】 成 GET /admin/keyword/list  api
     * @param perms
     * @return
     */
    private Collection<String> toApi(Set<String> perms) {
        //1:是超级管理员吗
        if(perms.contains("*")){
            return Arrays.asList("*");
        }
        String basicPackage = "com.qf.controller";
        //当前系统暂时所有权限
        List<Permission> permissions = PermissionUtil.listPermission(ac, basicPackage);
        return permissions.stream().filter(permission -> {
            if(perms.contains(permission.getRequiresPermissions().value()[0])){
                return true;
            }else{
                return false;
            }
        }).map(Permission::getApi).collect(Collectors.toSet());

    }


    /**
     * 退出
     * /logout
     */
    @PostMapping("/logout")
    public Object logout(){
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return ResponseUtil.ok();
    }
}
